// CherryMerry ( Mikhail Tomilenko ), Reverse Entertainment, 2021-2024

#include "../Public/NF_Character.h"

#include <NifestGame/ActorComponents/Public/PlayerHealthManager.h>
#include <NifestGame/ActorComponents/Public/PlayerLevelManager.h>
#include <NifestGame/ActorComponents/Public/PlayerUIManager.h>
#include <NifestGame/ActorComponents/Public/PlayerMovementManager.h>
#include <NifestGame/ActorComponents/Public/PlayerCombatManager.h>
#include <NifestGame/Core/Public/NF_GameInstance.h>

#include "Camera/CameraComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include <Kismet/GameplayStatics.h>

ANF_Character::ANF_Character()
{
	PrimaryActorTick.bCanEverTick = false;

	Camera = CreateDefaultSubobject<UCameraComponent>("Camera");
	Camera->SetupAttachment(RootComponent);	
	Camera->bUsePawnControlRotation = true;

	HealthManager = CreateDefaultSubobject<UPlayerHealthManager>("HealthManager");
	LevelManager = CreateDefaultSubobject<UPlayerLevelManager>("LevelManager");
	UIManager = CreateDefaultSubobject<UPlayerUIManager>("UIManager");
	MovementManager = CreateDefaultSubobject<UPlayerMovementManager>("MovementManager");
	CombatManager = CreateDefaultSubobject<UPlayerCombatManager>("CombatManager");
}

void ANF_Character::BeginPlay()
{
	Super::BeginPlay();
	
}

void ANF_Character::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void ANF_Character::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAxis(TEXT("MoveForward"), this, &ANF_Character::MoveForward);
	PlayerInputComponent->BindAxis(TEXT("MoveRight"), this, &ANF_Character::MoveRight);
	PlayerInputComponent->BindAxis(TEXT("RotateX"), this, &APawn::AddControllerYawInput);
	PlayerInputComponent->BindAxis(TEXT("RotateY"), this, &APawn::AddControllerPitchInput);

	/* Jump */
	PlayerInputComponent->BindAction(TEXT("Jump"), IE_Pressed, this, &ACharacter::Jump);
	PlayerInputComponent->BindAction(TEXT("Jump"), IE_Released, this, &ACharacter::StopJumping);
	/* Crouch */
	PlayerInputComponent->BindAction(TEXT("Crouch"), IE_Pressed, MovementManager, &UPlayerMovementManager::StartCrouching);
	PlayerInputComponent->BindAction(TEXT("Crouch"), IE_Released, MovementManager, &UPlayerMovementManager::StopCrouching);
	/* Sprint */
	PlayerInputComponent->BindAction(TEXT("Sprint"), IE_Pressed, MovementManager, &UPlayerMovementManager::StartSprinting);
	PlayerInputComponent->BindAction(TEXT("Sprint"), IE_Released, MovementManager, &UPlayerMovementManager::StopSprinting);
	/* Dash */
	PlayerInputComponent->BindAction(TEXT("Dash"), IE_Pressed, MovementManager, &UPlayerMovementManager::Dash);
	/* Interact */
	PlayerInputComponent->BindAction(TEXT("Interact"), IE_Pressed, this, &ANF_Character::PlayerInteract);
	/* Attack */
	PlayerInputComponent->BindAction(TEXT("Attack"), IE_Pressed, CombatManager, &UPlayerCombatManager::Attack);
	/* Block attack */
	PlayerInputComponent->BindAction(TEXT("BlockAttack"), IE_Pressed, CombatManager, &UPlayerCombatManager::BlockIncomingDamage);
	PlayerInputComponent->BindAction(TEXT("BlockAttack"), IE_Released, CombatManager, &UPlayerCombatManager::StopBlockIncomingDamage);
	/* Ability */
	PlayerInputComponent->BindAction(TEXT("Ability"), IE_Pressed, CombatManager, &UPlayerCombatManager::UseAbility);
	/* Ultimate */
	PlayerInputComponent->BindAction(TEXT("Ultimate"), IE_Pressed, CombatManager, &UPlayerCombatManager::UseUltimate);
}

void ANF_Character::MoveForward(float Value)
{
	FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
	AddMovementInput(Direction, Value);
}

void ANF_Character::MoveRight(float Value)
{
	FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
	AddMovementInput(Direction, Value);
}

void ANF_Character::UpdatePlayerSpeed_Implementation(float SpeedToSet, bool bCrouched)
{
	UCharacterMovementComponent* MovementComponent = GetCharacterMovement();

	if (bCrouched != true)
	{
		MovementComponent->MaxWalkSpeed = SpeedToSet;
	}
	else
	{
		MovementComponent->MaxWalkSpeedCrouched = SpeedToSet;
	}
}

void ANF_Character::Initialize_Implementation()
{
	/* Variables initilization */
		/* LevelManager */
	int32 CurrentPlayerLVL = LevelManager->CurrentLVL;
		/* HealthManager */
	float HealthToSet = LevelManager->GetHealthFromLVL(CurrentPlayerLVL);
	float ShieldToSet = LevelManager->GetShieldFromLVL(CurrentPlayerLVL);
		/* UIManager */
	UIManager->PlayerHUDClass = PlayerHUD;
	UIManager->RespawnMenuClass = RespawnMenu;
		/* MovementManager */
	MovementManager->StaminaDrainTime = StaminaDrainTime;
	MovementManager->StaminaRefillTime = StaminaRefillTime;
	MovementManager->DelayBeforeRefill = DelayBeforeRefill;
	/* Variables initialized */

	/* Functions initilization */
		/* LevelManaher */
	LevelManager->UpdateLVL();
		/* HealthManager */
	HealthManager->UpdateHealthAndShield(HealthToSet, ShieldToSet);
		/* UIManager */
	UIManager->CreateHUDWidget();
	UIManager->PlayerHUDMenu->PlayerShieldWidget->UpdateWidgetInfo(HealthManager->CurrentShield, HealthManager->MaxShield);
	UIManager->PlayerHUDMenu->PlayerHealthWidget->UpdateWidgetInfo(HealthManager->CurrentHealth, HealthManager->MaxHealth);
	UIManager->PlayerHUDMenu->PlayerLVLInfoWidget->UpdateWidgetInfo(LevelManager->CurrentLVL, LevelManager->CurrentEXP, LevelManager->MaxEXPOnLVL, LevelManager->PercentOnLVL);
	UIManager->PlayerHUDMenu->PlayerStaminaWidget->UpdateWidgetInfo(MovementManager->CurrentStamina, MovementManager->MaxStamina);
	/* Functions initialized */

	GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, FString::Printf(TEXT("Founded LVL: %f"), CurrentPlayerLVL));
	GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, FString::Printf(TEXT("Founded Health to set: %f"), HealthToSet));
	GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, FString::Printf(TEXT("Founded Shield to set: %f"), ShieldToSet));

	UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(GetWorld());
	II_Core* CoreInterface = Cast<II_Core>(GameInstance);

	if (CoreInterface)
	{
		UE_LOG(LogTemp, Warning, TEXT("Interface is valid, level opened"))
			CoreInterface->Execute_LevelLoaded(GameInstance);
	}
}

void ANF_Character::UpdatePlayerComponentsAfterLVLUp()
{
	int32 CurrentPlayerLVL = LevelManager->CurrentLVL;
	float HealthToUpdate = LevelManager->GetHealthFromLVL(CurrentPlayerLVL);
	float ShieldToUpdate = LevelManager->GetShieldFromLVL(CurrentPlayerLVL);

	HealthManager->UpdateHealthAndShield(HealthToUpdate, ShieldToUpdate);
}

void ANF_Character::PlayerInteract()
{
	FVector InteractStart = Camera->GetComponentLocation();
	FVector InteractEnd = InteractStart + Camera->GetForwardVector() * InteractTraceLength;

	FHitResult HitResult;
	FCollisionQueryParams Params;
	Params.AddIgnoredActor(this);

	if (GetWorld()->LineTraceSingleByChannel(HitResult, InteractStart, InteractEnd, ECollisionChannel::ECC_Visibility, Params, FCollisionResponseParams()))
	{
	}
}
